package com.exthirteen.textgamescript.service;

import com.exthirteen.textgamescript.config.CommonConfig;
import com.exthirteen.textgamescript.entity.AuthConfig;
import com.exthirteen.textgamescript.entity.LicenseKey;
import com.exthirteen.textgamescript.websocket.CommonSocketClient;
import com.exthirteen.textgamescript.websocket.WebSocketClientListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * <p>
 * 启动时运行
 * </p>
 *
 * @author exthirteen
 * @since 2025/5/5
 */
@Component
@Slf4j
public class RunService implements ApplicationRunner {

    @Value("${wechat-mmtls-config.ws-url}")
    private String socketUrl;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private AuthConfigService authConfigService;

    @Resource
    private LicenseKeyService licenseKeyService;

    //socket池
    private final static Map<String, CommonSocketClient> socketPool = new HashMap<>();

    //socket活跃时间
    private final static Map<String, Long> activityTimeMap = new ConcurrentHashMap<>();

    @Override
    public void run(ApplicationArguments args) {
        //设置回调地址
        AuthConfig config = authConfigService.getConfig();
        CommonConfig.CALLBACK_URL = config.getCallbackUrl();
    }

    /**
     * 添加socket客户端
     * @param licenseKey licenseKey
     */
    public void addClient(LicenseKey licenseKey){
        try {
            CommonSocketClient client = new CommonSocketClient(applicationContext) {
                @Override
                protected Map<String, String> getWsHeaders() {
                    return Collections.emptyMap();
                }

                @Override
                protected Supplier<String> getUrlSupplier() {
                    return () -> socketUrl + licenseKey.getLicense();
                }

                @Override
                protected WebSocketClientListener getListener() {
                    return new WsClientListener(applicationContext, licenseKey);
                }
            };
            if (client.getClient().getSocketClient().isOpen()){
                socketPool.put(licenseKey.getLicense(),client);
                setActivityTime(licenseKey.getLicense());
            }
        } catch (Exception e) {
            log.error("初始化socket失败, licenseKey: {}",licenseKey.getLicense(),e);
        }
    }

    //更新socket客户端
    public void updateClient(){
        //清理已断开的socket连接
        //用于存储需要删除的键
        Set<String> keysToRemove = new HashSet<>();
        //获取不活跃的链接进行清理
        int activeTime = 59;
        activityTimeMap.forEach((key, value) -> {
            if (System.currentTimeMillis() - value > activeTime * 1000) {
                keysToRemove.add(key);
            }
        });
        keysToRemove.forEach(key -> {
            socketPool.forEach((licenseKey, client) -> {
                if (licenseKey.equals(key)){
                    try {
                        if (client.getClient().getSocketClient().isOpen()){
                            client.close();
                        }
                    } catch (Exception e) {
                        log.error("移除socket失败, licenseKey: {}",licenseKey,e);
                    }
                }
            });
        });
        keysToRemove.clear();
        for (Map.Entry<String, CommonSocketClient> entry : socketPool.entrySet()) {
            if (!entry.getValue().getClient().getSocketClient().isOpen()){
                try {
                    keysToRemove.add(entry.getKey());
                } catch (Exception e) {
                    log.error("移除socket失败, licenseKey: {}",entry.getKey(),e);
                }
            }
        }
        //遍历键集并删除
        for (String key : keysToRemove) {
            socketPool.remove(key);
            activityTimeMap.remove(key);
        }
        List<LicenseKey> unExpiredLicenseKey = licenseKeyService.getUnExpiredLicenseKey();
        //查询不存在socket池中的licenseKey
        for (LicenseKey licenseKey : unExpiredLicenseKey) {
            if (!socketPool.containsKey(licenseKey.getLicense())){
                addClient(licenseKey);
            }
        }
        //查询socket池中不存在的licenseKey
        List<String> keys = unExpiredLicenseKey.stream().map(LicenseKey::getLicense).collect(Collectors.toList());
        for (Map.Entry<String, CommonSocketClient> entry : socketPool.entrySet()) {
            if (!keys.contains(entry.getKey())){
                try {
                    entry.getValue().close();
                } catch (Exception e) {
                    log.error("移除socket失败, licenseKey: {}",entry.getKey(),e);
                }
            }
        }
    }

    /**
     * 移除socket客户端
     * @param license license
     */
    public static void removeClient(String license){
        socketPool.remove(license);
    }

    /**
     * 设置socket活跃时间
     * @param license
     */
    public static void setActivityTime(String license){
        activityTimeMap.put(license, System.currentTimeMillis());
    }
}
